package freespiritsocial.io.user.ui.fragment.post

import android.media.MediaMetadataRetriever
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import androidx.core.os.bundleOf
import androidx.core.widget.addTextChangedListener
import androidx.exifinterface.media.ExifInterface
import androidx.lifecycle.lifecycleScope
import androidx.navigation.navOptions
import androidx.recyclerview.widget.GridLayoutManager
import com.beloo.widget.chipslayoutmanager.ChipsLayoutManager
import com.beloo.widget.chipslayoutmanager.SpacingItemDecoration
import com.google.android.gms.maps.model.LatLng
import com.google.android.libraries.places.api.model.Place
import com.luck.picture.lib.entity.LocalMedia
import com.permissionx.guolindev.PermissionX
import com.scwang.smart.refresh.layout.util.SmartUtil.dp2px
import freespiritsocial.io.user.R
import freespiritsocial.io.user.base.BaseFragment
import freespiritsocial.io.user.data.model.PlaceItem
import freespiritsocial.io.user.data.model.UploadPostEvent
import freespiritsocial.io.user.data.model.bean.PlaceAutocompleteBean.Companion.LOCATION_API
import freespiritsocial.io.user.data.model.bean.PostPojo
import freespiritsocial.io.user.databinding.FrgEditPostBinding
import freespiritsocial.io.user.ext.hideSoftKeyboard
import freespiritsocial.io.user.ext.init
import freespiritsocial.io.user.ui.adapter.AddMediaAdapter
import freespiritsocial.io.user.ui.adapter.AddTagAdapter
import freespiritsocial.io.user.ui.helper.GoogleApiHelper
import freespiritsocial.io.user.viewmodel.PostDetailViewModel
import freespiritsocial.io.user.weight.BottomCancelDialog
import freespiritsocial.io.user.weight.PictureDialog
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import me.hgj.jetpackmvvm.ext.nav
import me.hgj.jetpackmvvm.ext.navigateAction
import java.io.File
import java.io.FileOutputStream
import java.io.InputStream
import java.util.*


/**
 * @description 编辑帖子
 */
class EditPostFrg: BaseFragment<PostDetailViewModel,FrgEditPostBinding>() {
    private val googleApiHelper by lazy(LazyThreadSafetyMode.NONE) {
        GoogleApiHelper(requireContext())
    }
    private val oldFileList by lazy(LazyThreadSafetyMode.NONE) {
        val value = mViewModel.data.value
        value?.fileList
    }
    var hasLocationImagePath: String? = null

    private var selectPlace: PlaceItem? = null

    private val addMediaAdapter: AddMediaAdapter by lazy(LazyThreadSafetyMode.NONE) {
        AddMediaAdapter().apply {
            setOnItemChildClickListener { adapter,view,position ->
                hideSoftKeyboard(requireActivity())
                when (view.id) {
                    R.id.tv_add_media -> {
                        pictureDialog.show(childFragmentManager,"picture")
                    }
                    R.id.iv_close -> {
                        mViewModel.hasChange = true
                        val value = mViewModel.data.value
                        val path = data[position]
                        val removeSuccess = pictureDialog.removeData(path)
                        if (path == hasLocationImagePath) {
                            resetLocationName(value!!)
                        }
                        //移除失败代表不是相册的数据
                        if (!removeSuccess) {
                            pictureDialog.setMax(pictureDialog.maxSize + 1)
                            oldFileList?.remove(data[position])
                        }
                        removeAt(position)
                        if (data.isEmpty()) {
                            mViewModel.data.value = value?.also { it.localCover = null }
                            addData(0,"")
                        } else if (data.first().isNotEmpty()) {
                            addData(0,"")
                        }
                        mViewModel.canUpload.set(value?.canUpload())
                    }
                }
            }
        }
    }
    private val addTagAdapter by lazy(LazyThreadSafetyMode.NONE) {
        val list = arrayListOf<String>().also {
            it.addAll(mViewModel.data.value!!.tagList)
            if (it.last().isNotEmpty()) it.add("")
        }
        AddTagAdapter(list).apply {
            setOnItemChildClickListener { adapter,view,position ->
                hideSoftKeyboard(requireActivity())
                when (view.id) {
                    R.id.iv_add_tag -> {
                        nav().navigateAction(R.id.action_editPostFrg_to_searchTagFrg)
                    }
                    R.id.iv_close -> {
                        mViewModel.hasChange = true
                        removeAt(position)
                        mViewModel.data.value?.tagName = null
                        data.forEach {
                            mViewModel.data.value?.addTag(it)
                        }
                    }
                }
            }
        }
    }

    private val pictureDialog: PictureDialog by lazy(LazyThreadSafetyMode.NONE) {
        PictureDialog(this,6) { list ->
            mViewModel.hasChange = true
            addMediaAdapter.data.clear()
            val first = list.firstOrNull()?.also { file ->
                mViewModel.data.value = mViewModel.data.value?.also { it.localCover = file.outPutPath }
                mViewModel.canUpload.set(mViewModel.data.value?.canUpload())
            }
            val localMedia = first ?: return@PictureDialog addMediaAdapter.addData(listOf(""))
            if (list.size == 6) {
                addMediaAdapter.addData(list.map { it.outPutPath })
            } else {
                val isImage = localMedia.mimeType.contains("image")
                mViewModel.data.value?.fileType = if (isImage) 2 else 1
                if (isImage) {
                    addMediaAdapter.addData(list.mapTo(arrayListOf()) { it.outPutPath }.also { arrayList ->
                        oldFileList?.let { arrayList.addAll(it) }
                        if (arrayList.size < 6)
                            arrayList.add(0,"")
                    })
                } else addMediaAdapter.addData(list.map { it.outPutPath })
            }
            autoCheckLocationName(list)
        }
    }

    /**
     * 检查文件是否有地址存在
     */
    private fun autoCheckLocationName(list: ArrayList<LocalMedia>) {
        PermissionX.init(this).permissions("android.permission.ACCESS_MEDIA_LOCATION").request { _,_,_ ->
            val data = mViewModel.data.value ?: return@request
            if (!data.locationName.isNullOrEmpty() && hasLocationImagePath == null) return@request
            if (list.find { it.outPutPath == hasLocationImagePath } == null) {
                resetLocationName(data)
            }
            lifecycleScope.launch(Dispatchers.IO) {
                for (i in list.indices) {
                    val path = list[i].realPath
                    val isImage = list[i].mimeType.contains("image")
                    val latLong = withContext(Dispatchers.Default) {
                        if (isImage) checkImageLocation(path) else checkVideoLocation(path)
                    } ?: continue
                    hasLocationImagePath = list[i].outPutPath
                    Log.e("csw","autoCheckLocationName: lat:${latLong[0]} , lng:${latLong[1]}")
                    mViewModel.getLocationByLatLng(latLong[0],latLong[1]) {
                        googleApiHelper.fetchPlace(it.place_id) {
                            selectPlace = PlaceItem(it.latLng,address = it.address,it.id)
//                            eventViewModel.placeSelectEvent.postValue(it to 0)
                        }
                    }
                    return@launch
                }
            }
        }
    }

    private fun resetLocationName(data: PostPojo) {
        data.clearAddress()
        mViewModel.data.value = data
        hasLocationImagePath = null
        selectPlace = null
    }

    private fun copyFieUriToInnerStorage(uri: Uri,destFile: File) {
        var inputStream: InputStream? = null
        var fileOutputStream: FileOutputStream? = null
        try {
            inputStream = requireContext().contentResolver.openInputStream(uri) ?: return
            fileOutputStream = FileOutputStream(destFile)
            val buffer = ByteArray(4096)
            var redCount: Int
            while (inputStream.read(buffer).also { redCount = it } >= 0) {
                fileOutputStream.write(buffer,0,redCount)
            }
        } catch (e: Exception) {
        } finally {
            try {
                if (fileOutputStream != null) {
                    fileOutputStream.flush()
                    fileOutputStream.fd.sync()
                    fileOutputStream.close()
                }
                inputStream?.close()
            } catch (e: Exception) {
            }
        }
    }


    private suspend fun checkVideoLocation(path: String): DoubleArray? = withContext(Dispatchers.Default) {
        var latLng: DoubleArray? = null
        val createTempFile = File.createTempFile("temp",".mp4",requireContext().externalCacheDir)
        copyFieUriToInnerStorage(Uri.fromFile(File(path)),createTempFile)
        val mediaMetadataRetriever = MediaMetadataRetriever()
        mediaMetadataRetriever.setDataSource(createTempFile.toString())
        val locationStr = mediaMetadataRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_LOCATION)
        mediaMetadataRetriever.release()
        createTempFile.delete()
        if (!locationStr.isNullOrEmpty()) {
            val chars: CharArray = locationStr.toCharArray()
            var latitude = ""
            var longitude = ""
            for (i in chars.indices) {
                if ((chars[i] == '+' || chars[i] == '-') && i > 0) {
                    latitude = locationStr.substring(1,i)
                    longitude = locationStr.substring(i + 1,chars.size - 1)
                    break
                }
            }
            val dLat = latitude.toDouble()
            val dLon = longitude.toDouble()
            latLng = doubleArrayOf(dLat,dLon)
        }
        latLng
    }

    private fun checkImageLocation(path: String): DoubleArray? {

        var exifInterface: ExifInterface? = null
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            val uri = MediaStore.setRequireOriginal(Uri.fromFile(File(path)))
            var stream: InputStream? = null
            uri.runCatching {
                stream = requireContext().contentResolver.openInputStream(this) ?: return@runCatching
                exifInterface = ExifInterface(stream!!)
                stream!!.close()
            }.onFailure { stream?.close() }
        } else {
            exifInterface = ExifInterface(path)
        }
        return exifInterface?.latLong
    }

    private fun splicingTags(types: List<String>,apiType: Int = LOCATION_API) = StringBuilder().apply {
        types.forEach {
            when (it) {
                Place.Type.PARK.name -> append("Parks").append(",")
                Place.Type.NATURAL_FEATURE.name -> append("Natural feature").append(",")
                Place.Type.POINT_OF_INTEREST.name -> append("Point of interest").append(",")
                Place.Type.BAR.name -> append("Bars").append(",")
                Place.Type.CAFE.name -> append("Cafes").append(",")
                Place.Type.NIGHT_CLUB.name -> append("Clubs").append(",")
                Place.Type.MUSEUM.name -> append("Museums").append(",")
                Place.Type.RESTAURANT.name -> append("Restaurants").append(",")
            }
        }
    }.toString()

    var popId: Int? = null

    override fun layoutId(): Int = R.layout.frg_edit_post

    override fun initView(savedInstanceState: Bundle?) = with(mDatabind) {
        arguments?.getParcelable<PostPojo>("data")?.let {
            mViewModel.data.value = it.copy()
            mViewModel.isEdit.set(true)
        }
        arguments?.getInt("popId")?.let {
            popId = it
        }
        model = mViewModel
        click = Click()
        tvCaption.addTextChangedListener {
            mViewModel.hasChange = true
            mViewModel.canUpload.set(mViewModel.data.value?.canUpload())
        }
        recyclerViewImages.init(addMediaAdapter,GridLayoutManager(requireContext(),3),hasEmpty = false,isScroll = false)
        recyclerViewTags.init(
            addTagAdapter,
            ChipsLayoutManager.newBuilder(requireContext())
                .setOrientation(ChipsLayoutManager.HORIZONTAL)
                .build(),
            hasEmpty = false,isScroll = false
        ).addItemDecoration(SpacingItemDecoration(dp2px(14f),dp2px(14f)))
        initFileList()
        mViewModel.canUpload.set(mViewModel.data.value?.canUpload())
    }

    private fun initFileList() {
        val value = mViewModel.data.value
        val fileList = oldFileList ?: return
        if (fileList.size == 6) return addMediaAdapter.setList(fileList)
        if (value?.isVideo == false) {
            addMediaAdapter.addData(0,fileList)
            addMediaAdapter.addData(0,"")
        } else addMediaAdapter.addData(value?.coverUrl ?: "")
        pictureDialog.setMax(6 - fileList.filter { it.isNotEmpty() }.size)
        value?.localCover = value?.coverUrl
    }

    override fun createObserver() {
        super.createObserver()
        eventViewModel.onBackPressed.observe(this) {
            mDatabind.click?.cancel()
        }
        eventViewModel.tagSelectEvent.observe(this) {
            mViewModel.data.value?.addTag(it)
            addTagAdapter.setList(mViewModel.data.value!!.tagList)
            addTagAdapter.addData("")
            mViewModel.hasChange = true
        }
        eventViewModel.placeSelectEvent.observe(this) { pair ->
            val (it,apiType) = pair
            val post = mViewModel.data.value
            post?.clearAddress()
            hasLocationImagePath = null
            it.addressComponents?.asList()?.forEach {
                if (it.types.contains(Place.Type.COUNTRY.name.lowercase(Locale.ROOT))) {
                    post?.country = it.name
                    return@forEach
                }
                val hasCity = it.types.contains(Place.Type.LOCALITY.name.lowercase(Locale.ROOT))
                if (hasCity) {
                    post?.city = it.name
                    return@forEach
                }
                if (it.types.contains(Place.Type.ADMINISTRATIVE_AREA_LEVEL_2.name.lowercase(Locale.ROOT))) {
                    if (post?.city.isNullOrEmpty())
                        post?.city = it.name
                    return@forEach
                }
                if (it.types.contains(Place.Type.SUBLOCALITY.name.lowercase(Locale.ROOT))) {
                    post?.town = it.name
                    return@forEach
                }
                if (it.types.contains(Place.Type.ROUTE.name.lowercase(Locale.ROOT))) {
                    post?.street = it.name
                    return@forEach
                }
            }
            post?.locationName = it.address
            post?.address = it.name
            var tags = it.types?.map { it.name }?.let { splicingTags(it,apiType) }
            if (it.address.contains("Beach") || it.name.contains("Beach")) tags = "${tags}Beaches"
            else if (tags?.isNotEmpty() == true) tags = tags.removeSuffix(",")
            post?.venueCategoryLabel = tags
            mViewModel.canUpload.set(mViewModel.data.value?.canUpload())
            mViewModel.data.value = post
            mViewModel.hasChange = true
            selectPlace = PlaceItem(it.latLng,address = it.address,it.id)
        }
    }

    inner class Click {
        fun cancel() {
            hideSoftKeyboard(requireActivity())
            if (mViewModel.hasChange.not()) {
                nav().navigateUp()
                return
            }
            BottomCancelDialog(
                requireContext(),
                message = "Please note the information entered will be lost if you leave this screen without saving"
            ) {
                nav().navigateUp()
            }.show(childFragmentManager,"cancel")
        }

        fun getLocation() {
            hideSoftKeyboard(requireActivity())
            val bundleOf = Bundle()
            selectPlace?.let { bundleOf.putParcelable("place",it) }
            nav().navigateAction(R.id.action_editPostFrg_to_searchLocationFrg,bundleOf)
        }

        fun done() {
            hideSoftKeyboard(requireActivity())
            val postPojo = mViewModel.data.value ?: return
            postPojo.also { pojo -> pojo.uploadFiles = addMediaAdapter.data.map { File(it) } }
            if (mViewModel.isEdit.get()) {
                // 退出原先的详情 重新进入详情页
                mViewModel.editPost {
                    nav().navigateAction(
                        popId!!,
                        bundle = bundleOf(PostDetailFrg.KEY_DATA to it),
                        navOptions {
                            popUpTo(popId!!) { inclusive = true }
                            anim {
                                exit = me.hgj.jetpackmvvm.R.anim.exit
                                enter = me.hgj.jetpackmvvm.R.anim.enter
                                popEnter = me.hgj.jetpackmvvm.R.anim.popenter
                                popExit = me.hgj.jetpackmvvm.R.anim.popexit
                            }
                        })
                }
            } else {
                eventViewModel.uploadEvent.postValue(UploadPostEvent(postPojo))
                eventViewModel.changeMainTag.postValue(4)
                nav().navigateUp()
            }
        }

    }

    private val LocalMedia.outPutPath: String get() = if (isCompressed) compressPath else realPath
}